// function jspang () {
//   let web: String = "Hello World";
//   console.log(web)
// }

// jspang();

// function greeter (person: string) {
//   return "hello," + person;
// }

// let user = "jane user";

// document.body.innerHTML = greeter(user);


// interface Person {
//   firstName: string,
//   lastName: string
// }

// function greeters (person: Person) {
//   return "Hello, " +  person.firstName + ' ' + person.lastName;
// }

// let users = {  firstName: 'jane', lastName: 'user'};

// document.body.innerHTML = greeters(users);

// class Student {
//   fullname: string,
//   constructor (public firstname, public middleinitial, public lastname) {
//     this.fullname = firstname + ' ' + middleinitial + ' ' + lastname;
//   }
// }

// interface Persons {
//   firstname: string,
//   lastname: string
// }

// function gtrrtesss (person: Person) {
//   return "Hello, " + person.firstName + ' ' + person.lastName;
// }
// class Student {
//   fullname: string;
//   constructor (public firstname, public middleinitial, public lastname) {
//     this.fullname = firstname + ' ' + middleinitial + ' ' + lastname;
//   }
// }

// let userss = new Student('jane', 'm.', 'user filter');

// // document.body.innerHTML = gtrrtesss(userss)


// // 基本静态类型 string number null undefined boolean void symbol


// const xiaojiejie : string [] = ['xx', 'xxx', 'xxxx'];
// class Person {}
// const dajiao : Person = new Person()
// const jiaoxiaojiejie :() => string =()=> { return 'dajiao' }
// // 对象静态类型  数组类型   类类型  函数类型

// // 类型注解
// // 类型推断


// // 函数返回类型
// // function sayHello () : void {
// //   console.log('hello world')
// // }

// function errorFunction () : never {
//   throw new Error()
//   console.log('hello world')
// }

// function forNever () : never {
//   while (true) {}
//   console.log('hello world')
// }


// function add ({one, two} : { one: number, two: number}) {
//   return one + two
// }
// const total = add({one: 1, two: 2})

// function getNumber({one}:{one: number}) {
//   return one
// }
// const one = getNumber({one: 1})


// // 类型数组注解
// const numberArr : number[] = [1,2,3]
// const stringArr : string[] = ['a', 'b', 'c']
// const undefinedArr : undefined[] = [undefined, undefined]
// const arr : (number | string)[] = [1,  'str', 2]


// // type alias 类型别名
// type Lady = { name: string, age: number}
// class Madam {
//   name: string;
//   age: number;
// }

// const xiaojiejiesss : Lady[] = [
//   {name: '1', age: 1},
//   {name: '2', age: 2},
// ]

// const xiaojiejiess : Madam[] = [
//   {name: '1', age: 1},
//   {name: '2', age: 2},
// ]

// const xiaojiejies : {name: string, age: number}[] = [
//   {name: '1', age: 1},
//   {name: '2', age: 2},
// ]


// // 元组  特定类型排列
// const xiaojie1 : (string | number)[] = ['dajiao', 'tea', 28];
// const xiaojie2 : [string, string, number] = ['dajiao', 'tra', 28];
// // csv
// const xiaojie3 : [string, string, number][] = [
//   ['dajiao', 'tra', 28],
//   ['liuying', 'tea', 28],
//   ['curhui', 'tea', 28]
// ]


// // 接口 interface
// interface Girl {
//   name: string;
//   age: number;
//   bust: number;
//   waistline ?: number // ?: 可有可无
// }

// const gril = {
//   name: '大脚',
//   age: 18,
//   bust: 94,
//   waistline: 150
// }

// const screenResume = (gril : Girl ) => {
//   gril.age < 24 && gril.bust >= 90 && console.log(gril.name + '进入面试');
//   gril.age >= 24 || gril.bust < 90 && console.log(gril.name + '你被淘汰');
// }

// const getResume = (gril: Girl) => {
//   console.log(gril.name + '年龄是' + gril.age)
//   console.log(gril.name + '胸围是' + gril.bust)
//   gril.waistline && console.log(gril.name + '腰围是' + gril.waistline)
// }

// screenResume(gril)
// getResume(gril)


// // 初始接口 interface
// interface Girl2 {
//   name: string;
//   age: number;
//   bust: number;
//   waistline ?: number; // ?: 可有可无
//   [propname : string] : any;
//   say(): string;
// }


// // 接口之间继承
// interface Teacher extends Girl2 {
//   teach(): string;
// }

// // 类继承接口
// class XiaoJieJie implements Girl2 {
//   name = '大脚';
//   age = 18;
//   bust = 90;
//   say () {
//     return '欢迎光临， 红浪漫洗浴!!'
//   }
// }

// const gril2 = {
//   name: '大脚',
//   age: 18,
//   bust: 94,
//   waistline: 150,
//   sex: '女',
//   say () {
//     return '欢迎光临， 红浪漫洗浴!'
//   },
//   teach () {
//     return '老师上课!'
//   }
// }

// const screenResume2 = (gril : Girl2 ) => {
//   gril2.age < 24 && gril2.bust >= 90 && console.log(gril2.name + '进入面试');
//   gril2.age >= 24 || gril2.bust < 90 && console.log(gril2.name + '你被淘汰');
// }

// const getResume2 = (gril: Girl2) => {
//   console.log(gril2.name + '年龄是' + gril2.age)
//   console.log(gril2.name + '胸围是' + gril2.bust)
//   gril2.waistline && console.log(gril2.name + '腰围是' + gril2.waistline)
//   gril2.sex && console.log(gril2.name + '腰围是' + gril2.sex)
// }

// const getResume3 = (gril: Teacher) => {
//   console.log(gril2.name + '年龄是' + gril2.age)
//   console.log(gril2.name + '胸围是' + gril2.bust)
//   gril2.waistline && console.log(gril2.name + '腰围是' + gril2.waistline)
//   gril2.sex && console.log(gril2.name + '腰围是' + gril2.sex)
// }

// screenResume2(gril2)
// getResume2(gril2)
// // getResume3(gril2)



// // 类的构造函数
// class Persons {
//   constructor(public name: string) {}
// }
// const person = new Persons('jshupang')
// console.log(person.name);

// // 子类 想要设置构造函数， 就必须super， 、、 父类无特定constructor,子类继承也要super()

// class Teacher extends Person {
//   constructor(public age: number) {
//     super()
//   }
// }
// const teacher = new Teacher(18)
// console.log(teacher.age)

// // 类的getter， setter， static
// // private 和 getter setter的 用处。 _age是私有的，那类的外部就没办法改变，所以这时候可以用setter属性进行改变。
// // 不想new对象，直接使用这个方法，ts提供快捷方式，用static声明的属性和方法，不需要进行声明对象，就可以直接使用。  static

// class GirlStatic {
//   static sayLove () {
//     return ' I Love you'
//   }
// }

// console.log(GirlStatic.sayLove())


// // 抽象类  和 只读属性的使用

// // 只读属性
// class PersonOnlyRead {
//   public readonly _name: string
//   constructor(name: string) {
//     this._name = name
//   }
// }

// const personOnlyRead = new PersonOnlyRead('jshupang')
// console.log(personOnlyRead._name)

// class Person {
//   public name: string;
//   public sayHello() {
//     console.log(this.name + 'say hello')
//   }
// }
// // 以下属于类的外部
// const person = new Person()
// person.name = 'jspang';
// person.sayHello();
// console.log(person.name)

// 抽象类和抽象方法有一个比较深的认识。其实在工作中我们也会把这样的需求用接口来实现。


// 抽象类的使用
// 什么是抽象类那？我给大家举个例子，比如我开了一个红浪漫洗浴中心，里边有服务员，有初级技师，高级技师，每一个岗位我都写成一个类，那代码就是这样的。（注释掉刚才写的代码）

// class Waiter {}

// class BaseTeacher {}

// class seniorTeacher {}

// abstract class Grils{
//   abstract skill()  //因为没有具体的方法，所以我们这里不写括号
// }

// class Waiter extends Grils {
//   skill () {
//     console.log('大爷， 请喝水!')
//   }
// }

// class BaseTeacher extends Grils {
//   skill () {
//     console.log('大爷，来个泰式按摩吧!')
//   }
// }

// class seniorTeacher extends Grils {
//   skill () {
//     console.log('大爷，来个SPA全身按摩吧!')
//   }
// }


// 联合类型和类型保护（类型守护）
// 联合类型和相关的类型保护只是，需要注意的是，只有联合类型存在的情况下，菜需要类型保护。皮特的类型注解，并不需要我们这种特殊操作。
// 所谓联合类型，可以认为一个变量可能有两种或两种以上的类型。用代码举个例子，声明两个接口Waiter(服务员)接口和Teacher(技师)接口，然后在写一个judgeWho(判断是谁)的方法，里边传入一个animal(任意值)，这时候可以能是Waiter,也可能是Teacher。所以我们使用了联合类型，关键符号是|(竖线)。

// // 联合类型
// interface Waiter {
//   anjiao: boolean;
//   say: () => {};
// }

// interface Teacher {
//   anjiao: boolean;
//   skill: () => {};
// }

// function judgeWho(animal: Waiter | Teacher) {}

// 没进行类型保护就会报错
// function judgeWho (animal: Waiter | Teacher) {
//   animal.say();
// }


// 类型保护（类型断言）
// interface Waiter {
//   anjiao: boolean;
//   say: () => {};
// }

// interface Teacher {
//   anjiao: boolean;
//   skill: () => {};
// }

// function judgeWho(animal: Waiter | Teacher) {
//   if (animal.anjiao) {
//     (animal as Teacher).skill();
//   }else {
//     (animal as Waiter).say();
//   }
// }

// // 类型保护 -  in 语法
// // 判断 接口是否有 对应方法
// function judgeWhoTwo (animal: Waiter | Teacher) {
//   if ("skill" in animal) {
//     animal.skill();
//   } else {
//     animal.say();
//   }
// }

// 类型保护户 - typeof 语法


// 如果不进行类型判断，不然就会因为类型不一致导致表达式语法报错
// function add (first: string | number, second: string | number) {
//   return first + second;
// }

// // 正确解决方法
// function add (first: string | number, second: string | number) {
//   if (typeof first === "string" || typeof second === "string") {
//     return `${first}${second}`;
//   }
//   return first + second;
// }


// // 类型保护户 - instanceof 语法     (判断对象类型，  instanceof更合适)

// class NumberObj {
//   count: number;
// }

// // 不做类型保护，这段代码肯定是报错的，  有可能是object并没有count属性值
// // function addObj (first: object | NumberObj, second: object | NumberObj) {
// //   return first.count + second.count;
// // }

// // 报错不要紧，直接使用instanceof语法进行判断一下，就可以解决问题 || instanceof  只能用在类上
// function addObj (first: object | NumberObj, second: object | NumberObj) {
//   if (first instanceof NumberObj && second instanceof NumberObj) {
//     return first.count + second.count;
//   }
//   return 0;
// }


// 枚举类型 enum

// // 初级程序员写法：
// function getServe1 (status: number) {
//   if (status === 0) {
//     return "message";
//   } else if (status === 1) {
//     return "SPA";
//   } else if (status === 2) {
//     return "dabaojian";
//   }
// }

// const result = getServe1(0);
// console.log(`我要去${result}`)


// // 中级程序员写法:
// const Status = {
//   MESSAGE: 0,
//   SPA: 1,
//   DABAOJIAN: 2
// }

// function getServe2 (status: any) {
//   if (status === Status.MESSAGE) {
//     return "message";
//   } else if (status === Status.SPA) {
//     return "spa";
//   } else if (status === Status.DABAOJIAN) {
//     return "dabaojian";
//   }
// }

// const result2 = getServe2(Status.SPA);
// console.log(`我要去${result2}`)


// 高级程序员写法：
// enum Staus {
//   MESSAGE,
//   SPA,
//   DABAOJIAN
// }

// function getServe3 (status: any) {
//   if (status === Status.MESSAGE) {
//     return "message";
//   } else if (status === Status.SPA) {
//     return "spa";
//   } else if (status === Status.DABAOJIAN) {
//     return "dabaojian"
//   }
// }


// // 枚举类型的对应值
// const result3 = getServe3(Status.SPA);
// const result4 = getServe3(1);
// console.log(`我要去${result3}`)
// console.log(`我要去${result4}`)


// // 枚举通过下标反查
// console.log(Status.MESSAGE, Status[1])
// function errorFunction () : never {
//   throw new Error()
//   console.log('hello world')
// }

// function forNever () : never {
//   while (true) {}
//   console.log('hello world')
// }


// function add ({one, two} : { one: number, two: number}) {
//   return one + two
// }
// const total = add({one: 1, two: 2})

// function getNumber({one}:{one: number}) {
//   return one
// }
// const one = getNumber({one: 1})


// // 类型数组注解
// const numberArr : number[] = [1,2,3]
// const stringArr : string[] = ['a', 'b', 'c']
// const undefinedArr : undefined[] = [undefined, undefined]
// const arr : (number | string)[] = [1,  'str', 2]


// // type alias 类型别名
// type Lady = { name: string, age: number}
// class Madam {
//   name: string;
//   age: number;
// }

// const xiaojiejiesss : Lady[] = [
//   {name: '1', age: 1},
//   {name: '2', age: 2},
// ]

// const xiaojiejiess : Madam[] = [
//   {name: '1', age: 1},
//   {name: '2', age: 2},
// ]

// const xiaojiejies : {name: string, age: number}[] = [
//   {name: '1', age: 1},
//   {name: '2', age: 2},
// ]


// // 元组  特定类型排列
// const xiaojie1 : (string | number)[] = ['dajiao', 'tea', 28];
// const xiaojie2 : [string, string, number] = ['dajiao', 'tra', 28];
// // csv
// const xiaojie3 : [string, string, number][] = [
//   ['dajiao', 'tra', 28],
//   ['liuying', 'tea', 28],
//   ['curhui', 'tea', 28]
// ]


// // 接口 interface
// interface Girl {
//   name: string;
//   age: number;
//   bust: number;
//   waistline ?: number // ?: 可有可无
// }

// const gril = {
//   name: '大脚',
//   age: 18,
//   bust: 94,
//   waistline: 150
// }

// const screenResume = (gril : Girl ) => {
//   gril.age < 24 && gril.bust >= 90 && console.log(gril.name + '进入面试');
//   gril.age >= 24 || gril.bust < 90 && console.log(gril.name + '你被淘汰');
// }

// const getResume = (gril: Girl) => {
//   console.log(gril.name + '年龄是' + gril.age)
//   console.log(gril.name + '胸围是' + gril.bust)
//   gril.waistline && console.log(gril.name + '腰围是' + gril.waistline)
// }

// screenResume(gril)
// getResume(gril)


// // 初始接口 interface
// interface Girl2 {
//   name: string;
//   age: number;
//   bust: number;
//   waistline ?: number; // ?: 可有可无
//   [propname : string] : any;
//   say(): string;
// }


// // 接口之间继承
// interface Teacher extends Girl2 {
//   teach(): string;
// }

// // 类继承接口
// class XiaoJieJie implements Girl2 {
//   name = '大脚';
//   age = 18;
//   bust = 90;
//   say () {
//     return '欢迎光临， 红浪漫洗浴!!'
//   }
// }

// const gril2 = {
//   name: '大脚',
//   age: 18,
//   bust: 94,
//   waistline: 150,
//   sex: '女',
//   say () {
//     return '欢迎光临， 红浪漫洗浴!'
//   },
//   teach () {
//     return '老师上课!'
//   }
// }

// const screenResume2 = (gril : Girl2 ) => {
//   gril2.age < 24 && gril2.bust >= 90 && console.log(gril2.name + '进入面试');
//   gril2.age >= 24 || gril2.bust < 90 && console.log(gril2.name + '你被淘汰');
// }

// const getResume2 = (gril: Girl2) => {
//   console.log(gril2.name + '年龄是' + gril2.age)
//   console.log(gril2.name + '胸围是' + gril2.bust)
//   gril2.waistline && console.log(gril2.name + '腰围是' + gril2.waistline)
//   gril2.sex && console.log(gril2.name + '腰围是' + gril2.sex)
// }

// const getResume3 = (gril: Teacher) => {
//   console.log(gril2.name + '年龄是' + gril2.age)
//   console.log(gril2.name + '胸围是' + gril2.bust)
//   gril2.waistline && console.log(gril2.name + '腰围是' + gril2.waistline)
//   gril2.sex && console.log(gril2.name + '腰围是' + gril2.sex)
// }

// screenResume2(gril2)
// getResume2(gril2)
// getResume3(gril2)



// // 类
// class Ladys {
//   content = 'hi, shuaige!'
//   sayhello () {
//     return this.content
//   }
// }

// const goddess = new Ladys()
// console.log(goddess.sayhello())


// class xiaojiejieclass extends Ladys {
//   sayLove () {
//     return 'i love you'
//   }
// }

// const goddess2 = new xiaojiejieclass();
// console.log(goddess2.sayLove())
// console.log(goddess2.sayhello())

// // super 关键字   调用父类方法 继承中


// // 类的内部和类的外部
// // public private protected

// class Person2 {
//   // public private protected  
//   protected name: string;
//   public sayHello () {
//     console.log(this.name + 'say hello')
//   }
// }

// class Teacher extends Person2 {
//   public sayBye () {
//     this.name
//   }
// }

// const person = new Person2();
// person.name = 'jshupang';
// person.sayHello()
// console.log()
// console.log(person.name)


// 函数泛型 - 难点 

// function join(first: string | number, second: string | number) {
//   return `${first}${second}`
// }

// join("jspang", ".com");

// 初始泛型概念 - generic
// 泛型：[generic - 通用,泛指的意思]，最简单的理解，泛型就是泛指的类型。


// function join<JSPang>(frist: JSPang, second: JSPang) {
//   return `${frist}${second}`;
// }
// join<string>("jspang", ".com");

// // 如果是number类型，就直接再调用方法的时候进行更改就可以了
// join<number>(1, 2);


// // 泛型中数组的使用
// // 如果传递过来的值要求是数字，如何用泛型进行定义那?两种方法，第一种是直接使用[]，第二种是使用Array<>

// // 第一种写法：
// function myFun <ANY> (params: ANY[]) {
//   return params;
// }
// myFun < string > ["123", "344"];


// // 第二种写法：
// function mmyFun <ANY> (params: Array<ANY>) {
//   return params;
// }
// mmyFun < string > ["123", "456"];


// // 多个泛型的定义
// // 比如第一个泛型用T，第二个用P代表
// fucntion join<T,P>(first: T, second: P) {
//   return `${first}${second}`;
// }
// join <number, string> (1, "2");


// // 泛型的类型推断
// function join<T,P> (first: T, second: P) {
//   return `${first}${second}`;
// }
// join(1, "2");


// 类中泛型 - 难点
// 先编写一个基本的类，SelectGirl。 

// class SelectGirl {
//   constructor(private grils: string []) {}
//   getGirl(index: number): string {
//     return this.grils[index];
//   }
// }

// const selectGirl = new SelectGirl(["大脚", "刘英", "晓红"]);
// console.log(selectGirl.getGirl(1));

// 复杂代码用泛型
// class SelectGirl {
//   constructor(private girls: string[] | number[]) {}
//   getGirl(index: number): string | number {
//     return this.girls[index]
//   }
// }

// constructor 构造器

// 用泛型重构代码，<>
// class SelectGirl<T> {
//   constructor (private girls: T[]) {}
//   getGirl(index: number): T {
//     return this.girls[index];
//   }
// }

// // 是通过自身类型推断出来的。并没有对泛型的值进行确定
// const selectGirl = new SelectGirl(['dajiao','liuying','xiaohong']);
// console.log(selectGirl.getGirl(1));

// 对泛型的值进行确定
// const selectGirl = new SelectGirl<string>(['dajiao','liuying','xiaohong']);

// 泛型中的继承 （interface）
// 改成
// return this.grils[index].name;

// interface Girl {
//   name: string;
// }

// // 有了接口后用extends关键字实现泛型继承
// class SelectGirl <T extends Gril> {
//   ...
// }

// 这句代码的意思是泛型里必须有一个name属性，因为它继承了Girl接口。


// 泛型继承（interface）

// interface Girl {
//   name: string;
// }

// class SelectGirl <T extends Girl> {
//   constructor(private girls: T[]){}
//   getGirl(index: number): string {
//     return this.girls[index].name;
//   }
// }

// const selectGirl = new SelectGirl([
//   {name: 'dajiao1'},
//   {name: 'dajiao2'},
//   {name: 'dajiao3'},
// ]);
// console.log(selectGirl.getGirl(1));


// 泛型约束

// class SelectGirl <T> {
//   constructor(private girls: T[]) {}
//   getGirl(index: number): T {
//     return this.girls[index];
//   }
// }

// 泛型约束 - extends number|string
// class SelectGirl <T extends string | number> {
//   constructor(private girls: T[]) {}
//   getGirl(index: number): T {
//     return this.girls[index];
//   }
// }

// const selectGirl = new SelectGirl <string> (["dajiao1", "dajiao2", "dajiao3"]);
// console.log(selectGirl.getGirl(1));


// 初始typescript的命名空间 NammeSpace
